You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
133 lines
3.3 KiB
133 lines
3.3 KiB
"use client";
|
|
|
|
import { useEffect, useMemo, useState } from "react";
|
|
import {
|
|
getQuestionAnswersStorageKey,
|
|
hasQuestionAnswerValue,
|
|
} from "@/components/questions/question-answer-storage";
|
|
import InformationSheet from "@/components/ui/information-sheet";
|
|
import type { MarriageField, MarriagePhoneFieldValue } from "@/hooks/marriage/types";
|
|
import { useMarriageSectionsQuery } from "@/hooks/marriage/use-sections";
|
|
|
|
type AnswerPaceSheetProps = {
|
|
continueLabel: string;
|
|
description: string;
|
|
slug: string;
|
|
title: string;
|
|
};
|
|
|
|
type StoredQuestionAnswers = {
|
|
fields?: unknown;
|
|
};
|
|
|
|
function isMarriageField(value: unknown): value is MarriageField {
|
|
if (!value || typeof value !== "object") {
|
|
return false;
|
|
}
|
|
|
|
const field = value as Partial<MarriageField>;
|
|
|
|
return (
|
|
typeof field.key === "string" &&
|
|
typeof field.label === "string" &&
|
|
typeof field.type === "string" &&
|
|
(field.value === null ||
|
|
typeof field.value === "string" ||
|
|
typeof field.value === "number" ||
|
|
typeof field.value === "boolean" ||
|
|
isMarriagePhoneFieldValue(field.value))
|
|
);
|
|
}
|
|
|
|
function isMarriagePhoneFieldValue(
|
|
value: unknown,
|
|
): value is MarriagePhoneFieldValue {
|
|
if (!value || typeof value !== "object") {
|
|
return false;
|
|
}
|
|
|
|
const phoneValue = value as Partial<MarriagePhoneFieldValue>;
|
|
|
|
return (
|
|
typeof phoneValue.countryCode === "string" &&
|
|
typeof phoneValue.phoneNumber === "string"
|
|
);
|
|
}
|
|
|
|
function hasStoredQuestionProgress(slugs: readonly string[]) {
|
|
try {
|
|
return slugs.some((slug) => {
|
|
const rawValue = window.localStorage.getItem(
|
|
getQuestionAnswersStorageKey(slug),
|
|
);
|
|
|
|
if (!rawValue) {
|
|
return false;
|
|
}
|
|
|
|
const storedValue = JSON.parse(rawValue) as StoredQuestionAnswers;
|
|
const fields = Array.isArray(storedValue.fields)
|
|
? storedValue.fields.filter(isMarriageField)
|
|
: [];
|
|
|
|
return fields.some((field) => hasQuestionAnswerValue(field.value));
|
|
});
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
export default function AnswerPaceSheet({
|
|
continueLabel,
|
|
description,
|
|
slug,
|
|
title,
|
|
}: AnswerPaceSheetProps) {
|
|
const { data: sections, isSuccess } = useMarriageSectionsQuery();
|
|
const [hasSeenSheet, setHasSeenSheet] = useState(true);
|
|
const [hasLocalProgress, setHasLocalProgress] = useState(true);
|
|
const storageKey = `marriage:sections:${slug}:answer-pace-sheet-seen`;
|
|
const sectionSlugs = useMemo(
|
|
() => sections?.map((section) => section.slug) ?? [slug],
|
|
[sections, slug],
|
|
);
|
|
|
|
const hasAnySectionProgress = useMemo(() => {
|
|
if (!sections?.length) {
|
|
return true;
|
|
}
|
|
|
|
return sections.some(
|
|
(section) => section.current_step > 0 || section.completion_percent >= 1,
|
|
);
|
|
}, [sections]);
|
|
|
|
const isOpen =
|
|
isSuccess && !hasSeenSheet && !hasLocalProgress && !hasAnySectionProgress;
|
|
|
|
useEffect(() => {
|
|
setHasSeenSheet(window.sessionStorage.getItem(storageKey) === "true");
|
|
setHasLocalProgress(hasStoredQuestionProgress(sectionSlugs));
|
|
}, [sectionSlugs, storageKey]);
|
|
|
|
useEffect(() => {
|
|
if (!isOpen) {
|
|
return;
|
|
}
|
|
|
|
window.sessionStorage.setItem(storageKey, "true");
|
|
}, [isOpen, storageKey]);
|
|
|
|
if (!isOpen) {
|
|
return null;
|
|
}
|
|
|
|
return (
|
|
<InformationSheet
|
|
icon="play"
|
|
title={title}
|
|
description={description}
|
|
buttons={continueLabel}
|
|
/>
|
|
);
|
|
}
|